﻿/*
AwpAdmin, an admin tool for Battlefield 3
Copyright (C) 2011 agentwite, Timi, Unseen, AlCapwn

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

You can contact us at http://bf3admin.codeplex.com/.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Net.Battlefield3;
using System.IO;
using System.Globalization;

namespace AwpAdminTool
{
    /// <summary>
    /// Represents an admin of the server.
    /// </summary>
    public class Admin : MarshalByRefObject
    {
        CultureInfo c = CultureInfo.GetCultureInfo("en-US");

        #region Properties
        /// <summary>
        /// Gets or sets the display name of the admin.
        /// </summary>
        /// <value>The display name of the admin.</value>
        /// <remarks>
        /// This property does not reflect the ingame name of the admin.
        /// </remarks>
        public string Name
        {
            get { return AdminElement.Attribute("name").Value; }
            set { AdminElement.Attribute("name").Value = value; Save(); }
        }

        /// <summary>
        /// Gets or sets the required GUID of the admin.
        /// </summary>
        /// <value>The GUID of the admin.</value>
        /// <remarks>
        /// All admins are identified by their GUID.
        /// </remarks>
        public string Guid
        {
            get { return AdminElement.Attribute("guid").Value; }
            set { AdminElement.Attribute("guid").Value = value; Save(); }
        }

        /// <summary>
        /// Gets or sets the rank of the admin.
        /// </summary>
        /// <value>The numerical rank of the admin.</value>
        public int Rank
        {
            get { return Convert.ToInt32(AdminElement.Attribute("rank").Value, c); }
            set { AdminElement.Attribute("rank").Value = value < 1 ? "0" : value.ToString(c); Save(); } //min value is 0
        }

        /// <summary>
        /// Gets the last logon of this admin.
        /// </summary>
        /// <value>The last logon of this admin.</value>
        public DateTime LastLogOn
        {
            get { return XmlConvert.ToDateTime(AdminElement.Attribute("lastLogon").Value, XmlDateTimeSerializationMode.Utc); }
            internal set { AdminElement.Attribute("lastLogon").Value = XmlConvert.ToString(value, XmlDateTimeSerializationMode.Utc); Save(); }
        }
        #endregion

        AwpAdmin ParentAdmin;
        XElement AdminsElement; //will be the root element stored in AwpAdmin.AdminSettings.
        XElement AdminElement; //will be the xelement specific to the admin.
        XNamespace x; //namespace
        internal void Save()
        {
            string fileLocation = Path.IsPathRooted(ParentAdmin.AdminsFile) ? ParentAdmin.AdminsFile : ParentAdmin.WorkingDirectory + ParentAdmin.AdminsFile;

            lock (AdminsElement)
                if (AdminElement.Document == null) AdminsElement.Add(AdminElement);

            AdminElement.Document.Save(fileLocation);
        }

        internal void Load(string guid, string name = "")
        {
            XElement admin = GetAdminXml(guid);
            

            if (admin != null) //exists
                AdminElement = admin;
            else
            {
                AdminElement = new XElement(x + "admin",
                    new XAttribute("name", name),
                    new XAttribute("guid", guid),
                    new XAttribute("rank", 0),
                    new XAttribute("lastLogon", "")
                    );

                //AdminsElement.Add(AdminElement);

                //dont save because adds an element for every Player.GetAdmin().
                //Save();
            }
        }

        //this is done to lock the element such that AdminsElement isnt modified during enumeration
        XElement GetAdminXml(string guid)
        {
            lock (AdminsElement)
                foreach (var a in AdminsElement.Elements(x + "admin"))
                {
                    if (a.Attribute("guid").Value == guid) return a;
                }
            return null;
        }

        #region Ctors
        /// <summary>
        /// Creates a new admin for the specified <see cref="AwpAdmin"/>.
        /// </summary>
        /// <param name="awpAdmin">The parent <see cref="AwpAdmin"/> that the <see cref="Admin"/> will belong to.</param>
        /// <param name="guid">The GUID of the new <see cref="Admin"/>.</param>
        /// <remarks>
        /// If the <see cref="Admin"/> already exists, the settings for that <see cref="Admin"/> will be loaded.
        /// </remarks>
        public Admin(AwpAdmin awpAdmin, string guid)
        {
            ParentAdmin = awpAdmin;
            AdminsElement = awpAdmin.AdminSettings;
            x = AwpAdmin.XmlNamespace;

            Load(guid);
        }

        /// <summary>
        /// Creates a new admin for the specified <see cref="AwpAdmin"/>.
        /// </summary>
        /// <param name="awpAdmin">The parent <see cref="AwpAdmin"/> that the <see cref="Admin"/> will belong to.</param>
        /// <param name="guid">The GUID of the new <see cref="Admin"/>.</param>
        /// <param name="name">Gets the display name of the new <see cref="Admin"/>.</param>
        /// <remarks>
        /// If the <see cref="Admin"/> already exists, the settings for that <see cref="Admin"/> will be loaded.<para />
        /// The <paramref name="name"/> serves no purpose other than to show who the <paramref name="guid"/> belongs to.
        /// </remarks>
        public Admin(AwpAdmin awpAdmin, string guid, string name)
        {
            ParentAdmin = awpAdmin;
            AdminsElement = awpAdmin.AdminSettings;
            x = AwpAdmin.XmlNamespace;

            Load(guid, name);
        }

        /// <summary>
        /// Creates a new admin for the <see cref="Player"/> of the specified <see cref="AwpAdmin"/>.
        /// </summary>
        /// <param name="awpAdmin">The parent <see cref="AwpAdmin"/> that the <see cref="Admin"/> will belong to.</param>
        /// <param name="player">The <see cref="Player"/> off which the new <see cref="Admin"/> will be based.</param>
        /// <remarks>
        /// If the <see cref="Admin"/> already exists, the settings for that <see cref="Admin"/> will be loaded.
        /// </remarks>
        public Admin(AwpAdmin awpAdmin, Player player) : this(awpAdmin, player.Guid, player.Name)
        {

        }
        #endregion
    }
}
